#include "asm/includes.h"
#include "asm/rtc.h"
#include "asm/rtc_port.h"
#include "asm/rtc_calculate.h"
#include "asm/cpu.h"
#include "asm/power/p33.h"

static struct rtc_data *__this = NULL;


#define WRITE_ALARM     BIT(1)
#define READ_ALARM      BIT(5)

#define WRITE_RTC       BIT(0)
#define READ_RTC        BIT(4)

#define OS_ENTER_CRITICAL()  \
		CPU_CRITICAL_ENTER(); \

#define OS_EXIT_CRITICAL()  \
		CPU_CRITICAL_EXIT()

#define IRTC_X2IE(x)      JL_P33->RTC_CON = ((JL_P33->RTC_CON & ~(BIT(1))) | ((x & 0x01) << 1))
#define IRTC_X512IE(x)    JL_P33->RTC_CON = ((JL_P33->RTC_CON & ~(BIT(2))) | ((x & 0x01) << 2))
#define IRTC_WKIE(x)      JL_P33->RTC_CON = ((JL_P33->RTC_CON & ~(BIT(4))) | ((x & 0x01) << 4))


/*----------------------------------------------------------------------------*/
/**@brief 	读IRTC
   @param 	cmd：读指令 r_time：读出的日期
   @return  void
   @note  	void read_IRTC(u8 cmd, sstruct sys_time *r_time)
*/
/*----------------------------------------------------------------------------*/
static void read_IRTC(u8 cmd, struct sys_time *r_time)
{
    OS_ENTER_CRITICAL();

    u16 r_day;

    p33_cs_h(R3_RTC_CON0);
    p33_buf((P33_OR << 5) | (u8)((R3_RTC_CON0 & 0x300) >> 8));               //rd    //adr 3
    p33_buf((u8)(R3_RTC_CON0 & 0xff));       //wr    //adr 3
    p33_buf(cmd);


    p33_buf(0x0);
    r_day = p33_buf(0x0);
    r_day <<= 8;
    r_day += p33_buf(0x0);

    day_to_ymd(r_day, r_time);  //add：总天数换成：年-月-日

    r_time->hour = p33_buf(0x0);
    r_time->min  = p33_buf(0x0);
    r_time->sec  = p33_buf(0x0);

    //add：day day hour minute second
    //add: 按照由高到低，一次读1个byte
    p33_cs_l;

    OS_EXIT_CRITICAL();

}

/*----------------------------------------------------------------------------*/
/**@brief 	写IRTC
   @param 	cmd：写指令 w_time:写入日期
   @return  void
   @note  	void write_IRTC(u8 cmd, sstruct sys_time *w_time)
*/
/*----------------------------------------------------------------------------*/
static void write_IRTC(u8 cmd, struct sys_time *w_time)
{

    OS_ENTER_CRITICAL();
    u8 buf;
    u16 w_day;

    p33_cs_h(R3_RTC_CON0);
    p33_buf((u8)((R3_RTC_CON0 & 0x300) >> 8));               //rd    //adr 3
    p33_buf((u8)(R3_RTC_CON0 & 0xff));       //wr    //adr 3
    p33_buf(cmd);

    p33_buf(0);

    w_day = ymd_to_day(w_time);
    buf = (u8)(w_day >> 8);
    p33_buf(buf);
    buf = (u8)(w_day);
    p33_buf(buf);

    buf = w_time->hour;
    p33_buf(buf);

    buf = w_time->min;
    p33_buf(buf);

    buf = w_time->sec;
    p33_buf(buf);

    p33_cs_l;

    OS_EXIT_CRITICAL();

}

void rtc_set_alarm_ctrl(u8 set_alarm)
{

    u8 dat = p33_rx_1byte(R3_ALM_CON);

    if (set_alarm) {
        dat |= BIT(0);
    } else {
        dat &= ~BIT(0);
    }

    p33_tx_1byte(R3_ALM_CON, dat);
}

void rtc_write_time(struct sys_time *curr_time)
{
    rtc_set_alarm_ctrl(0);
    write_IRTC(WRITE_RTC, curr_time);
    rtc_set_alarm_ctrl(1);
}

void rtc_read_time(struct sys_time *curr_time)
{
    read_IRTC(READ_RTC, curr_time);
}

void rtc_write_alarm(struct sys_time *alarm_time)
{
    rtc_set_alarm_ctrl(0);
    write_IRTC(WRITE_ALARM, alarm_time);
    rtc_set_alarm_ctrl(1);
}
void rtc_read_alarm(struct sys_time *alarm_time)
{
    read_IRTC(READ_ALARM, alarm_time);
}


void __attribute__((weak)) alm_wakeup_isr(void)
{
    if (__this->cbfun) {
        __this->cbfun(0);
    }
}

static u8 alarm_wakeup_flag = 0;
static u8 get_alarm_wkup_flag(void)
{
    return alarm_wakeup_flag;
}

static void set_alarm_wkup_flag(u8 flag)
{
    alarm_wakeup_flag = flag;
}

static u8 read_RTC_POR_FLAG(void)
{
    u8 ret;
    ret = p33_rx_1byte(R3_RST_CON);

    return ret & BIT(7);
}

static void clr_RTC_POR_FLAG(void)
{
    u8 dat;
    dat = p33_rx_1byte(R3_RST_CON);
    dat |= BIT(6);
    p33_tx_1byte(R3_RST_CON, dat);
}


void rtc_time_dump(void)
{
    struct sys_time tmp_time;
    memset((u8 *)&tmp_time, 0, sizeof(tmp_time));
    rtc_read_time(&tmp_time);
    printf("rtc_rtc_read_time: %d-%d-%d %d:%d:%d\n",
           tmp_time.year,
           tmp_time.month,
           tmp_time.day,
           tmp_time.hour,
           tmp_time.min,
           tmp_time.sec);
}

int rtc_init(struct rtc_data *arg)
{
    __this = arg;

    JL_P33->RTC_CON |= BIT(13) | BIT(14) ;//| BIT(15); //BIT(15)清掉了就不能检查到关机闹钟唤醒

    if (__this->ldo_in) {
        p33_or_1byte(P3_ANA_CON2, BIT(0));    //使用内部ldo
    }

    ALM_CLK_SEL(__this->clk_sel);

    IRTC_X2IE(0);
    IRTC_X512IE(0);
    IRTC_WKIE(0);                      //WKUPIE 允许置1，否则 0

    if (__this->clk_sel == CLK_SEL_32K) {
        //32K_OSCO
        rtc_port_pr_in(0);
        rtc_port_pr_pu(0, 0);
        rtc_port_pr_pd(0, 0);
        rtc_port_pr_die(0, 0);
        /* 32K_OSCI */
        rtc_port_pr_in(1);
        rtc_port_pr_pu(1, 0);
        rtc_port_pr_pd(1, 0);
        rtc_port_pr_die(1, 0);

        u8 dat;
        dat = p33_rx_1byte(R3_OSL_CON);
        dat |= BIT(0);//doscen 晶振两脚模式,只用于32k晶振
        p33_tx_1byte(R3_OSL_CON, dat);
    }

    p33_or_1byte(P3_VLD_KEEP, BIT(7)); //连接到P33，否则会导致闹钟中断进不去

    clr_RTC_POR_FLAG();

    rtc_write_time(__this->default_sys_time);
    rtc_write_alarm(__this->default_alarm);
    /* rtc_time_dump(); */

    return 0;
}


/*		RTC TEST DEMO		*/
#define RTC_TEST_ENABLE		0

#if RTC_TEST_ENABLE

struct sys_time def_sys_time = {  //初始一下当前时间
    .year = 2020,
    .month = 1,
    .day = 1,
    .hour = 0,
    .min = 0,
    .sec = 0,
};

struct sys_time test_sys_time = {  //初始一下当前时间
    .year = 2021,
    .month = 2,
    .day = 2,
    .hour = 12,
    .min = 12,
    .sec = 12,
};

struct sys_time def_alarm = {     //初始一下目标时间，即闹钟时间
    .year = 2050,
    .month = 1,
    .day = 1,
    .hour = 0,
    .min = 0,
    .sec = 0,
};

struct sys_time test_alarm = {     //初始一下目标时间，即闹钟时间
    .year = 2050,
    .month = 1,
    .day = 1,
    .hour = 18,
    .min = 18,
    .sec = 18,
};

struct rtc_data rtc_data = {
    .default_sys_time = &def_sys_time,
    .default_alarm = &def_alarm,
    .cbfun = NULL,                      //闹钟中断的回调函数,用户自行定义
    .clk_sel = CLK_SEL_12M,
    .ldo_in = 0,
};

void rtc_test_demo()
{
    struct sys_time tmp_time;
    memset((u8 *)&tmp_time, 0, sizeof(tmp_time));

    rtc_init(&rtc_data);				//初始化rtc

    rtc_read_time(&tmp_time);						//读当前rtc时间
    printf("rtc_rtc_read_time_before: %d-%d-%d %d:%d:%d\n", tmp_time.year, tmp_time.month, tmp_time.day, tmp_time.hour, tmp_time.min, tmp_time.sec);	//打印读取时间值

    rtc_write_time(&test_sys_time); 		//修改rtc时间
    rtc_read_time(&tmp_time); 				//读修改后rtc时间
    printf("rtc_rtc_read_time_after: %d-%d-%d %d:%d:%d\n", tmp_time.year, tmp_time.month, tmp_time.day, tmp_time.hour, tmp_time.min, tmp_time.sec);		//打印修改后时间值

    rtc_read_alarm(&tmp_time); 					//读当前alarm时间
    printf("rtc_read_alarm_before: %d-%d-%d %d:%d:%d\n", tmp_time.year, tmp_time.month, tmp_time.day, tmp_time.hour, tmp_time.min, tmp_time.sec);	//打印读取闹钟时间值

    rtc_write_alarm(&test_alarm); 	//修改alarm时间
    rtc_read_alarm(&tmp_time); 		//读修改后alarm时间
    printf("rtc_read_alarm_after: %d-%d-%d %d:%d:%d\n", tmp_time.year, tmp_time.month, tmp_time.day, tmp_time.hour, tmp_time.min, tmp_time.sec);		//打印修改后闹钟时间值
}


#endif	//RTC_TEST_ENABLE



